<!DOCTYPE html>
<html lang="zh-CN,en,zh-TW,default">
  <head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/tree/4.2.0'>
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
    
  
  <!-- 渲染优化 -->
  <meta http-equiv='x-dns-prefetch-control' content='on' />
  <link rel='dns-prefetch' href='https://cdn.jsdelivr.net'>
  <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <!-- 页面元数据 -->
  
  <title>Spring Bean加载 源码解析 - Yayako&#39;s Blog</title>
  
    <meta name="keywords" content="源码,Spring">
  

  
    <meta name="description" content="Spring是如何实现bean加载的？Spring是如何创建单例bean如何解决循环依赖的的？">
  

  <!-- feed -->
  

  <!-- import meta -->
  

  <!-- link -->
  
    <link rel="shortcut icon" type='image/x-icon' href="https://halo-yayako.oss-cn-hangzhou.aliyuncs.com/icons8-lamb-96_1600147384617.png">
  

  <!-- import link -->
  

  
    
<link rel="stylesheet" href="/css/first.css">

  

  
  <link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/css/style.css"></noscript>
  

  <script id="loadcss"></script>

  

<script>if (/*@cc_on!@*/false || (!!window.MSInputMethodContext && !!document.documentMode)) document.write('\x3Cscript id="_iealwn_js" data-outver="11" src="https://support.dmeng.net/ie-alert-warning/latest.js">\x3C/script>'); </script>

</head>

  <body>
    

<header id="l_header" class="l_header always shadow blur "  >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fas fa-comments fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
          <li><a id="s-toc" class="s-toc fas fa-list fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/'>
          
            <img no-lazy class='logo' src='https://yayako-blog.oss-cn-hangzhou.aliyuncs.com/settings/icons8-doughnut-100.png'/>
          
          
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/
                  
                  
                  
                    id="categoriesJava"
                  >
                  Java
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/%E5%9F%BA%E7%A1%80/
                  
                  
                  
                    id="categoriesJavaE59FBAE7A180"
                  >
                  基础
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/JVM/
                  
                  
                  
                    id="categoriesJavaJVM"
                  >
                  JVM
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/J.U.C/
                  
                  
                  
                    id="categoriesJavaJUC"
                  >
                  J.U.C
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Golang/
                  
                  
                  
                    id="categoriesGolang"
                  >
                  Golang
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Golang/%E5%9F%BA%E7%A1%80
                  
                  
                  
                    id="categoriesGolangE59FBAE7A180"
                  >
                  基础
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E6%A1%86%E6%9E%B6/
                  
                  
                  
                    id="categoriesE6A186E69EB6"
                  >
                  框架
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E6%A1%86%E6%9E%B6/SSM/
                  
                  
                  
                    id="categoriesE6A186E69EB6SSM"
                  >
                  SSM
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/
                  
                  
                  
                    id="categoriesE4B8ADE997B4E4BBB6"
                  >
                  中间件
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/Redis/
                  
                  
                  
                    id="categoriesE4B8ADE997B4E4BBB6Redis"
                  >
                  Redis
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/MySQL/
                  
                  
                  
                    id="categoriesMySQL"
                  >
                  MySQL
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/MySQL/%E5%9F%BA%E7%A1%80/
                  
                  
                  
                    id="categoriesMySQLE59FBAE7A180"
                  >
                  基础
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/MySQL/InnoDB/
                  
                  
                  
                    id="categoriesMySQLInnoDB"
                  >
                  InnoDB
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E7%AE%97%E6%B3%95/
                  
                  
                  
                    id="categoriesE7AE97E6B395"
                  >
                  算法
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E7%AE%97%E6%B3%95/LeetCode/
                  
                  
                  
                    id="categoriesE7AE97E6B395LeetCode"
                  >
                  LeetCode
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87offer/
                  
                  
                  
                    id="categoriesE7AE97E6B395E58991E68C87offer"
                  >
                  剑指offer
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/
                  
                  
                  
                    id="categoriesE5B7A5E585B7"
                  >
                  工具
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/Linux/
                  
                  
                  
                    id="categoriesE5B7A5E585B7Linux"
                  >
                  Linux
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/Nginx/
                  
                  
                  
                    id="categoriesE5B7A5E585B7Nginx"
                  >
                  Nginx
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/Docker/
                  
                  
                  
                    id="categoriesE5B7A5E585B7Docker"
                  >
                  Docker
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%85%B6%E4%BB%96/
                  
                  
                  
                    id="categoriesE585B6E4BB96"
                  >
                  其他
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%85%B6%E4%BB%96/%E9%9D%A2%E7%BB%8F/
                  
                  
                  
                    id="categoriesE585B6E4BB96E99DA2E7BB8F"
                  >
                  面经
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
				</ul>
			</div>

      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fas fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="Search..." />
        </form>
      </div>

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fas fa-search fa-fw" target="_self" href='javascript:void(0)'></a></li>
				
				<li>
          <a class="s-menu fas fa-bars fa-fw" target="_self" href='javascript:void(0)'></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/
                  
                  
                  
                    id="categoriesJava"
                  >
                  Java
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/%E5%9F%BA%E7%A1%80/
                  
                  
                  
                    id="categoriesJavaE59FBAE7A180"
                  >
                  基础
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/JVM/
                  
                  
                  
                    id="categoriesJavaJVM"
                  >
                  JVM
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Java/J.U.C/
                  
                  
                  
                    id="categoriesJavaJUC"
                  >
                  J.U.C
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Golang/
                  
                  
                  
                    id="categoriesGolang"
                  >
                  Golang
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/Golang/%E5%9F%BA%E7%A1%80
                  
                  
                  
                    id="categoriesGolangE59FBAE7A180"
                  >
                  基础
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E6%A1%86%E6%9E%B6/
                  
                  
                  
                    id="categoriesE6A186E69EB6"
                  >
                  框架
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E6%A1%86%E6%9E%B6/SSM/
                  
                  
                  
                    id="categoriesE6A186E69EB6SSM"
                  >
                  SSM
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/
                  
                  
                  
                    id="categoriesE4B8ADE997B4E4BBB6"
                  >
                  中间件
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/Redis/
                  
                  
                  
                    id="categoriesE4B8ADE997B4E4BBB6Redis"
                  >
                  Redis
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/MySQL/
                  
                  
                  
                    id="categoriesMySQL"
                  >
                  MySQL
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/MySQL/%E5%9F%BA%E7%A1%80/
                  
                  
                  
                    id="categoriesMySQLE59FBAE7A180"
                  >
                  基础
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/MySQL/InnoDB/
                  
                  
                  
                    id="categoriesMySQLInnoDB"
                  >
                  InnoDB
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E7%AE%97%E6%B3%95/
                  
                  
                  
                    id="categoriesE7AE97E6B395"
                  >
                  算法
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E7%AE%97%E6%B3%95/LeetCode/
                  
                  
                  
                    id="categoriesE7AE97E6B395LeetCode"
                  >
                  LeetCode
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E7%AE%97%E6%B3%95/%E5%89%91%E6%8C%87offer/
                  
                  
                  
                    id="categoriesE7AE97E6B395E58991E68C87offer"
                  >
                  剑指offer
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/
                  
                  
                  
                    id="categoriesE5B7A5E585B7"
                  >
                  工具
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/Linux/
                  
                  
                  
                    id="categoriesE5B7A5E585B7Linux"
                  >
                  Linux
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/Nginx/
                  
                  
                  
                    id="categoriesE5B7A5E585B7Nginx"
                  >
                  Nginx
                </a>
                
              </li>
            
          
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%B7%A5%E5%85%B7/Docker/
                  
                  
                  
                    id="categoriesE5B7A5E585B7Docker"
                  >
                  Docker
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%85%B6%E4%BB%96/
                  
                  
                  
                    id="categoriesE585B6E4BB96"
                  >
                  其他
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/%E5%85%B6%E4%BB%96/%E9%9D%A2%E7%BB%8F/
                  
                  
                  
                    id="categoriesE585B6E4BB96E99DA2E7BB8F"
                  >
                  面经
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
          </ul>
        </li>
			</ul>
		</div>
	</div>
  </div>
</header>

    <div id="l_body">
      <div id="l_cover">
  
    
        <div id="half" class='cover-wrapper post search' style="display: ;">
          
            <div id='cover-backstretch'></div>
          
          <div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">Yayako's Blog</p>
    
    
      <p class="subtitle">「Shooting for the stars when I couldn't make a killing.」</p>
    
  </div>
  <div class='bottom'>
    
      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <input type="text" class="input u-search-input" placeholder="Have a nice day!" />
          <i class="icon fas fa-search fa-fw"></i>
        </form>
      </div>
    
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="/"
              
              
              id="home">
              <i class='fas fa-home fa-fw'></i><p>首页</p>
            </a>
          
            <a href="/categories/"
              
              
              id="categories">
              <i class='fas fa-folder-open fa-fw'></i><p>分类</p>
            </a>
          
            <a href="/archives/"
              
              
              id="archives">
              <i class='fas fa-archive fa-fw'></i><p>归档</p>
            </a>
          
            <a href="/tags/"
              
              
              id="tags">
              <i class='fas fa-tags fa-fw'></i><p>标签</p>
            </a>
          
            <a href="/friends/"
              
              
              id="friends">
              <i class='fas fa-link fa-fw'></i><p>友链</p>
            </a>
          
            <a href="/about/"
              
              
              id="about">
              <i class='fas fa-user fa-fw'></i><p>关于</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

          <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
        </div>
    
  
  </div>

      <div id="safearea">
        <div class="body-wrapper" id="pjax-container">
          

<div class='l_main'>
  <article class="article post white-box reveal md shadow article-type-post" id="post" itemscope itemprop="blogPost">
  


  
  <div class="article-meta" id="top">
    
    
    
      <h1 class="title">
        Spring Bean加载 源码解析
      </h1>
      <div class='new-meta-box'>
        
          
            
<div class='new-meta-item author'>
  <a class='author' href="/about" rel="nofollow">
    <img no-lazy src="https://yayako-blog.oss-cn-hangzhou.aliyuncs.com/settings/icons8-cat-100%20%282%29.png">
    <p>yayako</p>
  </a>
</div>

          
        
          
            <div class="new-meta-item date">
  <a class='notlink'>
    <i class="fas fa-calendar-alt fa-fw" aria-hidden="true"></i>
    <p>发布于：2020年6月7日</p>
  </a>
</div>

          
        
          
            
  <div class="new-meta-item browse leancloud">
    <a class='notlink'>
      
      <div id="lc-pv" data-title="Spring Bean加载 源码解析" data-path="/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/">
        <i class="fas fa-eye fa-fw" aria-hidden="true"></i>
        <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span>
        次浏览
      </div>
    </a>
  </div>


          
        
          
            
<div class="new-meta-item comments-count">
  
  <a href="/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/#comments">
    <i class="fas fa-comment-dots fa-fw"></i>
    <span class="valine-comment-count" data-xid="/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/">0</span>
    <span class="leancloud-comments-count">&nbsp;条评论</span>
  </a>
</div>


          
        
      </div>
    
  </div>


  
  
  <p>主要参考了《Spring源码深度解析》这本书。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">T <span class="title">getBean</span><span class="params">(String name, <span class="meta">@Nullable</span> Class&lt;T&gt; requiredType, <span class="meta">@Nullable</span> Object... args)</span></span></span><br><span class="line"><span class="function">        <span class="keyword">throws</span> BeansException </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> doGetBean(name, requiredType, args, <span class="keyword">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="doGetBean"><a href="#doGetBean" class="headerlink" title="doGetBean"></a>doGetBean</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> &lt;T&gt; <span class="function">T <span class="title">doGetBean</span><span class="params">(String name, <span class="meta">@Nullable</span> Class&lt;T&gt; requiredType, <span class="meta">@Nullable</span> Object[] args, <span class="keyword">boolean</span> typeCheckOnly)</span> <span class="keyword">throws</span> BeansException </span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<h2 id="1-转换对应beanName"><a href="#1-转换对应beanName" class="headerlink" title="1. 转换对应beanName"></a>1. 转换对应beanName</h2><p>因为创建bean时传入的参数name有可能是alias或者FactoryBean，所以需要另外解析。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> String beanName = transformedBeanName(name);</span><br></pre></td></tr></table></figure>
<h2 id="2-尝试从缓存中加载单例并将其实例化"><a href="#2-尝试从缓存中加载单例并将其实例化" class="headerlink" title="2. 尝试从缓存中加载单例并将其实例化"></a>2. 尝试从缓存中加载单例并将其实例化</h2><p>对于单例bean，因为他在spring容器中只会加载一次，后续在获取都会直接从单例缓存中获取。且因为缓存中记录的都是最原始的bean状态，所以还需将其实例化。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 先从缓存、实例工厂中检查是否有对应的实例（为了避免循环依赖）</span></span><br><span class="line"><span class="comment">// Eagerly check singleton cache for manually registered singletons.</span></span><br><span class="line">Object sharedInstance = getSingleton(beanName);</span><br><span class="line"><span class="comment">// 如果从缓存中得到了原始bean，即bean的原始状态，则需要对其实例化</span></span><br><span class="line"><span class="keyword">if</span> (sharedInstance != <span class="keyword">null</span> &amp;&amp; args == <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line">        <span class="keyword">if</span> (isSingletonCurrentlyInCreation(beanName)) &#123;</span><br><span class="line">            logger.trace(</span><br><span class="line">                    <span class="string">&quot;Returning eagerly cached instance of singleton bean &#x27;&quot;</span></span><br><span class="line">                            + beanName</span><br><span class="line">                            + <span class="string">&quot;&#x27; that is not fully initialized yet - a consequence of a circular reference&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            logger.trace(<span class="string">&quot;Returning cached instance of singleton bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 返回对应的实例（实例本身或制定方法返回的实例），即实例化</span></span><br><span class="line">    bean = getObjectForBeanInstance(sharedInstance, name, beanName, <span class="keyword">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="3-原型模式的依赖检查"><a href="#3-原型模式的依赖检查" class="headerlink" title="3. 原型模式的依赖检查"></a>3. 原型模式的依赖检查</h2><p>缓存中尝试加载失败。</p>
<p>只有单例模式中才回去尝试解决循环依赖问题，原型模式中将会抛异常</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 如果这个实例正在创建中，那么现在可能处于循环依赖情况下</span></span><br><span class="line"><span class="comment">// Fail if we&#x27;re already creating this bean instance:</span></span><br><span class="line"><span class="comment">// We&#x27;re assumably within a circular reference.</span></span><br><span class="line"><span class="keyword">if</span> (isPrototypeCurrentlyInCreation(beanName)) &#123; <span class="comment">// true表示循环依赖</span></span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> BeanCurrentlyInCreationException(beanName);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="4-检测parentBeanFactory"><a href="#4-检测parentBeanFactory" class="headerlink" title="4. 检测parentBeanFactory"></a>4. 检测parentBeanFactory</h2><p>在缓存取不到数据的情况下，如果父类存在并且当前加载的xml配置文件中不包含当前加载beanName所对应的配置，则交给父类工厂来加载。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查工厂中是否有该bean definition</span></span><br><span class="line"><span class="comment">// Check if bean definition exists in this factory.</span></span><br><span class="line">BeanFactory parentBeanFactory = getParentBeanFactory();</span><br><span class="line"><span class="comment">// 父工厂不为空并且当前加载的xml配置文件中不包含beanName所对应的配置，则由父类工厂来加载</span></span><br><span class="line"><span class="keyword">if</span> (parentBeanFactory != <span class="keyword">null</span> &amp;&amp; !containsBeanDefinition(beanName)) &#123;</span><br><span class="line">    <span class="comment">// 父工厂中寻找，递归</span></span><br><span class="line">    <span class="comment">// Not found -&gt; check parent.</span></span><br><span class="line">    String nameToLookup = originalBeanName(name);</span><br><span class="line">    <span class="keyword">if</span> (parentBeanFactory <span class="keyword">instanceof</span> AbstractBeanFactory) &#123;</span><br><span class="line">        <span class="keyword">return</span> ((AbstractBeanFactory) parentBeanFactory)</span><br><span class="line">            .doGetBean(nameToLookup, requiredType, args, typeCheckOnly);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (args != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">// Delegation to parent with explicit args.</span></span><br><span class="line">        <span class="keyword">return</span> (T) parentBeanFactory.getBean(nameToLookup, args);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (requiredType != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">// No args -&gt; delegate to standard getBean method.</span></span><br><span class="line">        <span class="keyword">return</span> parentBeanFactory.getBean(nameToLookup, requiredType);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> (T) parentBeanFactory.getBean(nameToLookup);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果不是仅仅做类型检查则是创建bean，需要进行记录</span></span><br><span class="line"><span class="keyword">if</span> (!typeCheckOnly) &#123;</span><br><span class="line">    markBeanAsCreated(beanName);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="5-将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition"><a href="#5-将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition" class="headerlink" title="5. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition"></a>5. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition</h2><p>因为从xml配置文件中读取到的bean信息是存储在GernericBeanDefinition中的，但是所有的bean后续处理都是针对于RootBeanDefinition的，所以需要进行转换，同时如果其父类bean不为空，将一并合并父类的属性。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 将存储xml配置文件的GernericBeanDefinition转换为RootBeanDefinition</span></span><br><span class="line"><span class="comment">// 如果当前beanName是子beanName的话同时会合并父类的相关属性</span></span><br><span class="line"><span class="keyword">final</span> RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);</span><br><span class="line">checkMergedBeanDefinition(mbd, beanName, args);</span><br></pre></td></tr></table></figure>
<h2 id="6-寻找依赖（depend-on）"><a href="#6-寻找依赖（depend-on）" class="headerlink" title="6. 寻找依赖（depend-on）"></a>6. 寻找依赖（depend-on）</h2><p>如果存在某些属性依赖其他bean，那么就需要先加载依赖的bean。所以在spring的加载顺寻中，在初始化一个bean的时候首先会初始化这个bean所对应的依赖。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 若存在依赖，则递归实例化依赖bean</span></span><br><span class="line"><span class="comment">// Guarantee initialization of beans that the current bean depends on.</span></span><br><span class="line">String[] dependsOn = mbd.getDependsOn();</span><br><span class="line"><span class="keyword">if</span> (dependsOn != <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="keyword">for</span> (String dep : dependsOn) &#123;</span><br><span class="line">        <span class="keyword">if</span> (isDependent(beanName, dep)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                mbd.getResourceDescription(),</span><br><span class="line">                beanName,</span><br><span class="line">                <span class="string">&quot;Circular depends-on relationship between &#x27;&quot;</span></span><br><span class="line">                + beanName</span><br><span class="line">                + <span class="string">&quot;&#x27; and &#x27;&quot;</span></span><br><span class="line">                + dep</span><br><span class="line">                + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 缓存依赖调用</span></span><br><span class="line">        registerDependentBean(dep, beanName);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            getBean(dep);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchBeanDefinitionException ex) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                mbd.getResourceDescription(),</span><br><span class="line">                beanName,</span><br><span class="line">                <span class="string">&quot;&#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27; depends on missing bean &#x27;&quot;</span> + dep + <span class="string">&quot;&#x27;&quot;</span>,</span><br><span class="line">                ex);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="7-针对不同的scope进行bean的创建"><a href="#7-针对不同的scope进行bean的创建" class="headerlink" title="7. 针对不同的scope进行bean的创建"></a>7. 针对不同的scope进行bean的创建</h2><p>spring会根据不同的scope进行其对应的初始化策略。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 针对不同的scope进行不同的bean初始化策略</span></span><br><span class="line"><span class="comment">// Create bean instance.</span></span><br><span class="line"><span class="keyword">if</span> (mbd.isSingleton()) &#123; <span class="comment">// singleton 单例</span></span><br><span class="line">    sharedInstance =</span><br><span class="line">        getSingleton(</span><br><span class="line">        beanName,</span><br><span class="line">        () -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> createBean(beanName, mbd, args);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (BeansException ex) &#123;</span><br><span class="line">                <span class="comment">// Explicitly remove instance from singleton cache: It</span></span><br><span class="line">                <span class="comment">// might have been put there</span></span><br><span class="line">                <span class="comment">// eagerly by the creation process, to allow for</span></span><br><span class="line">                <span class="comment">// circular reference resolution.</span></span><br><span class="line">                <span class="comment">// Also remove any beans that received a temporary</span></span><br><span class="line">                <span class="comment">// reference to the bean.</span></span><br><span class="line">                destroySingleton(beanName);</span><br><span class="line">                <span class="keyword">throw</span> ex;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (mbd.isPrototype()) &#123; <span class="comment">// prototype 原型</span></span><br><span class="line">    <span class="comment">// It&#x27;s a prototype -&gt; create a new instance.</span></span><br><span class="line">    Object prototypeInstance = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        beforePrototypeCreation(beanName);</span><br><span class="line">        prototypeInstance = createBean(beanName, mbd, args);</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        afterPrototypeCreation(beanName);</span><br><span class="line">    &#125;</span><br><span class="line">    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123; <span class="comment">// 其他</span></span><br><span class="line">    String scopeName = mbd.getScope();</span><br><span class="line">    <span class="keyword">final</span> Scope scope = <span class="keyword">this</span>.scopes.get(scopeName);</span><br><span class="line">    <span class="keyword">if</span> (scope == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(</span><br><span class="line">            <span class="string">&quot;No Scope registered for scope name &#x27;&quot;</span> + scopeName + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        Object scopedInstance =</span><br><span class="line">            scope.get(</span><br><span class="line">            beanName,</span><br><span class="line">            () -&gt; &#123;</span><br><span class="line">                beforePrototypeCreation(beanName);</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> createBean(beanName, mbd, args);</span><br><span class="line">                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                    afterPrototypeCreation(beanName);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IllegalStateException ex) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">            beanName,</span><br><span class="line">            <span class="string">&quot;Scope &#x27;&quot;</span></span><br><span class="line">            + scopeName</span><br><span class="line">            + <span class="string">&quot;&#x27; is not active for the current thread; consider &quot;</span></span><br><span class="line">            + <span class="string">&quot;defining a scoped proxy for this bean if you intend to refer to it from a singleton&quot;</span>,</span><br><span class="line">            ex);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="8-类型转换"><a href="#8-类型转换" class="headerlink" title="8. 类型转换"></a>8. 类型转换</h2><p>若得到的bean实例类型不是所需的类型，将返回的bean转换为requireType所指定的类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查当前bean实例类型是否符合所需类型</span></span><br><span class="line"><span class="comment">// Check if required type matches the type of the actual bean instance.</span></span><br><span class="line"><span class="keyword">if</span> (requiredType != <span class="keyword">null</span> &amp;&amp; !requiredType.isInstance(bean)) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);</span><br><span class="line">        <span class="keyword">if</span> (convertedBean == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> convertedBean;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (TypeMismatchException ex) &#123;</span><br><span class="line">        <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line">            logger.trace(</span><br><span class="line">                <span class="string">&quot;Failed to convert bean &#x27;&quot;</span></span><br><span class="line">                + name</span><br><span class="line">                + <span class="string">&quot;&#x27; to required type &#x27;&quot;</span></span><br><span class="line">                + ClassUtils.getQualifiedName(requiredType)</span><br><span class="line">                + <span class="string">&quot;&#x27;&quot;</span>,</span><br><span class="line">                ex);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> (T) bean;</span><br></pre></td></tr></table></figure>
<h1 id="FactoryBean的使用"><a href="#FactoryBean的使用" class="headerlink" title="FactoryBean的使用"></a>FactoryBean的使用</h1><p>工厂类接口，实现bean的实例化逻辑。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">FactoryBean</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    String OBJECT_TYPE_ATTRIBUTE = <span class="string">&quot;factoryBeanObjectType&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** </span></span><br><span class="line"><span class="comment">     * 返回由FactoryBean创建的bean实例</span></span><br><span class="line"><span class="comment">     * 如果是单例模式（isSingleton()返回true），则会将该实例放入单实例缓存池。 </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="function">T <span class="title">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 返回FactoryBean创建的bean类型 */</span></span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    Class&lt;?&gt; getObjectType();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 返回由FactoryBean创建的bean实例的作用域是singleton还是prototype */</span></span><br><span class="line">    <span class="function"><span class="keyword">default</span> <span class="keyword">boolean</span> <span class="title">isSingleton</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>当配置文件读取到的的class属性为FactoryBean时，通过getBean()方法返回的不是FactoryBean本身，而是FactoryBean#getObject()所返回的对象，相当于FactoryBean#getObject()<strong>代理</strong>了getBean()方法。</p>
<h1 id="getSingleton-——-缓存中获取单例bean"><a href="#getSingleton-——-缓存中获取单例bean" class="headerlink" title="getSingleton —— 缓存中获取单例bean"></a>getSingleton —— 缓存中获取单例bean</h1><p>Spring创建bean的原则：不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中，一旦下一个bean创建时需要依赖上个bean，则直接使用ObjectFactory。</p>
<ol>
<li><p>先从 <code>singletonObjects</code> 中获取实例，若存在，直接返回。</p>
</li>
<li><p>反之，上锁。再从 <code>earlySingletonObjects</code> 中获取实例，若存在，直接返回。</p>
</li>
<li><p>反之，获取该beanName对应的ObjectFactory，最后调用他的 <code>getObject</code> 来创建bean，并放入 <code>earlySingletonObjects</code> 中，并从 <code>singletonFactories</code> 中移除。</p>
</li>
</ol>
<p>对于这几个map：</p>
<ul>
<li><p>singletonObjects：bean name –&gt; bean instance</p>
</li>
<li><p>singletonFactories：bean name –&gt; ObjectFactory</p>
</li>
<li><p>earlySingletonObjects：bean name –&gt; bean instance，区别在于，当一个单例bean被放入该map后，就意味着不管bean是在创建中还是已经创建完成，都可以通过 getBean 方法获取到。目的是用于<strong>检测循环引用</strong>。</p>
</li>
<li><p>registerSingletons：用来保存当前所有已注册的bean。</p>
</li>
</ul>
<p><strong>源码分析</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">getSingleton</span><span class="params">(String beanName)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// true 设置表示允许早期依赖</span></span><br><span class="line">    <span class="keyword">return</span> getSingleton(beanName, <span class="keyword">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">getSingleton</span><span class="params">(String beanName, <span class="keyword">boolean</span> allowEarlyReference)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 1 从缓存（singletonObjects -- map）中是否存在实例</span></span><br><span class="line">    Object singletonObject = <span class="keyword">this</span>.singletonObjects.get(beanName);</span><br><span class="line">    <span class="keyword">if</span> (singletonObject == <span class="keyword">null</span> &amp;&amp; </span><br><span class="line">        <span class="comment">// 这个判断是否此bean正在创建中，首次创建的bean并不会进入，但在循环依赖中，A注入了B，B注入了A，当递归进行B的创建时，需要注入A时再到这里，会发现A已经被加入了正在创建池</span></span><br><span class="line">        isSingletonCurrentlyInCreation(beanName)) &#123;</span><br><span class="line">        <span class="comment">// 如果为空并且处于创建阶段，则对其加锁</span></span><br><span class="line">        <span class="keyword">synchronized</span> (<span class="keyword">this</span>.singletonObjects) &#123;</span><br><span class="line">            <span class="comment">// 2 从 earlySingletonObjects -- map 中获取实例</span></span><br><span class="line">            singletonObject = <span class="keyword">this</span>.earlySingletonObjects.get(beanName);</span><br><span class="line">            <span class="keyword">if</span> (singletonObject == <span class="keyword">null</span> &amp;&amp; allowEarlyReference) &#123;</span><br><span class="line">                <span class="comment">// 当某些方法需要提前初始化的时候会调用 addSingletonFactory 方法</span></span><br><span class="line">                <span class="comment">// 将对应的 ObjectFactory 初始化策略存储在 singletonFactories</span></span><br><span class="line">                ObjectFactory&lt;?&gt; singletonFactory = <span class="keyword">this</span>.singletonFactories.get(beanName);</span><br><span class="line">                <span class="keyword">if</span> (singletonFactory != <span class="keyword">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// 3 使用 ObjectFactory 的 getObject 来创建</span></span><br><span class="line">                    singletonObject = singletonFactory.getObject();</span><br><span class="line">                    <span class="comment">// 记录在缓存中，earlySingletonObjects 和 singletonFactories 互斥</span></span><br><span class="line">                    <span class="keyword">this</span>.earlySingletonObjects.put(beanName, singletonObject);</span><br><span class="line">                    <span class="keyword">this</span>.singletonFactories.remove(beanName);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 返回</span></span><br><span class="line">    <span class="keyword">return</span> singletonObject;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="从bean的实例中获取对象"><a href="#从bean的实例中获取对象" class="headerlink" title="从bean的实例中获取对象"></a>从bean的实例中获取对象</h1><p>从缓存中拿到的bean实例要通过 <code>getObjectForBeanInstance</code> 方法来进行检测正确性，就是检测当前bean是否是FactoryBean类型的bean，如果是，那就需要调用其 getObject() 作为返回值。</p>
<h2 id="getObjectForBeanInstance"><a href="#getObjectForBeanInstance" class="headerlink" title="getObjectForBeanInstance"></a>getObjectForBeanInstance</h2><ol>
<li><p>对FactoryBean正确性的检验</p>
</li>
<li><p>对非FactoryBean不作任何处理</p>
</li>
<li><p>对bean进行转换</p>
</li>
<li><p>将从Factory中解析bean的工作委托给 <code>getObjectFromFactoryBean</code></p>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 获取给定bean实例的对象，如果是FactoryBean，则根据需求返回bean实例本身或其创建的对象。 */</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">getObjectForBeanInstance</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">        Object beanInstance, String name, String beanName, <span class="meta">@Nullable</span> RootBeanDefinition mbd)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 若指定的name为FactoryBean（以“&amp;”为前缀）而instance又不是FactoryBean类型，则验证不通过</span></span><br><span class="line">    <span class="comment">// Don&#x27;t let calling code try to dereference the factory if the bean isn&#x27;t a factory.</span></span><br><span class="line">    <span class="keyword">if</span> (BeanFactoryUtils.isFactoryDereference(name)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanInstance <span class="keyword">instanceof</span> NullBean) &#123;</span><br><span class="line">            <span class="keyword">return</span> beanInstance;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!(beanInstance <span class="keyword">instanceof</span> FactoryBean)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> BeanIsNotAFactoryException(beanName, beanInstance.getClass());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (mbd != <span class="keyword">null</span>) &#123;</span><br><span class="line">            mbd.isFactoryBean = <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> beanInstance;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 现在我们有了一个bean实例，他可能是普通的bean，也可能是FactoryBean</span></span><br><span class="line">    <span class="comment">// 如果是FactoryBean，我们就使用它来创建一个bean实例，除非想要获取工厂实例</span></span><br><span class="line">    <span class="comment">// Now we have the bean instance, which may be a normal bean or a FactoryBean.</span></span><br><span class="line">    <span class="comment">// If it&#x27;s a FactoryBean, we use it to create a bean instance, unless the</span></span><br><span class="line">    <span class="comment">// caller actually wants a reference to the factory.</span></span><br><span class="line">    <span class="comment">// 在这里，如果他不是一个工厂bean，那么就直接返回</span></span><br><span class="line">    <span class="keyword">if</span> (!(beanInstance <span class="keyword">instanceof</span> FactoryBean)) &#123;</span><br><span class="line">        <span class="keyword">return</span> beanInstance;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 到这里就说明beanName对应一个FactoryBean，而我们想要的是一个普通的bean实例</span></span><br><span class="line">    <span class="comment">// 加载FactoryBean</span></span><br><span class="line">    Object object = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (mbd != <span class="keyword">null</span>) &#123;</span><br><span class="line">        mbd.isFactoryBean = <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 尝试从缓存中加载bean</span></span><br><span class="line">        object = getCachedObjectForFactoryBean(beanName);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (object == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 返回一个FactoryBean实例</span></span><br><span class="line">        <span class="comment">// Return bean instance from factory.</span></span><br><span class="line">        FactoryBean&lt;?&gt; factory = (FactoryBean&lt;?&gt;) beanInstance;</span><br><span class="line">        <span class="comment">// 如果beanName对应的bean实例为单例，将其缓存</span></span><br><span class="line">        <span class="comment">// Caches object obtained from FactoryBean if it is a singleton.</span></span><br><span class="line">        <span class="keyword">if</span> (mbd == <span class="keyword">null</span> &amp;&amp; containsBeanDefinition(beanName)) &#123;</span><br><span class="line">            <span class="comment">// 将GernericBeanDefinition转换为RootBeanDefinitio，合并父类相关属性</span></span><br><span class="line">            mbd = getMergedLocalBeanDefinition(beanName);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">boolean</span> synthetic = (mbd != <span class="keyword">null</span> &amp;&amp; mbd.isSynthetic());</span><br><span class="line">        <span class="comment">// 将解析工作委托给 getObjectFromFactoryBean</span></span><br><span class="line">        object = getObjectFromFactoryBean(factory, beanName, !synthetic);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> object;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="getObjectFromFactoryBean"><a href="#getObjectFromFactoryBean" class="headerlink" title="getObjectFromFactoryBean"></a>getObjectFromFactoryBean</h2><p>只做了单例判断，如果是单例模式，则需要保证全局唯一，并且对其做了缓存来提高性能，如果缓存中已经存有该bean，直接获取并返回，如果不存在或者为null，则进而交由 <code>doGetObjectFromFactoryBean</code> 。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">getObjectFromFactoryBean</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">        FactoryBean&lt;?&gt; factory, String beanName, <span class="keyword">boolean</span> shouldPostProcess)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 如果是单例模式并且该bean已经缓存</span></span><br><span class="line">    <span class="keyword">if</span> (factory.isSingleton() &amp;&amp; containsSingleton(beanName)) &#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (getSingletonMutex()) &#123;</span><br><span class="line">            Object object = <span class="keyword">this</span>.factoryBeanObjectCache.get(beanName);</span><br><span class="line">            <span class="keyword">if</span> (object == <span class="keyword">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 缓存值为null</span></span><br><span class="line">                object = doGetObjectFromFactoryBean(factory, beanName);</span><br><span class="line">                <span class="comment">// Only post-process and store if not put there already during getObject() call</span></span><br><span class="line">                <span class="comment">// above</span></span><br><span class="line">                <span class="comment">// (e.g. because of circular reference processing triggered by custom getBean</span></span><br><span class="line">                <span class="comment">// calls)</span></span><br><span class="line">                Object alreadyThere = <span class="keyword">this</span>.factoryBeanObjectCache.get(beanName);</span><br><span class="line">                <span class="keyword">if</span> (alreadyThere != <span class="keyword">null</span>) &#123;</span><br><span class="line">                    object = alreadyThere;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">// 后置处理</span></span><br><span class="line">                    <span class="keyword">if</span> (shouldPostProcess) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (isSingletonCurrentlyInCreation(beanName)) &#123;</span><br><span class="line">                            <span class="comment">// Temporarily return non-post-processed object, not storing it</span></span><br><span class="line">                            <span class="comment">// yet..</span></span><br><span class="line">                            <span class="keyword">return</span> object;</span><br><span class="line">                        &#125;</span><br><span class="line">                        beforeSingletonCreation(beanName);</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            object = postProcessObjectFromFactoryBean(object, beanName);</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">                            <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                                    beanName,</span><br><span class="line">                                    <span class="string">&quot;Post-processing of FactoryBean&#x27;s singleton object failed&quot;</span>,</span><br><span class="line">                                    ex);</span><br><span class="line">                        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                            afterSingletonCreation(beanName);</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">if</span> (containsSingleton(beanName)) &#123;</span><br><span class="line">                        <span class="keyword">this</span>.factoryBeanObjectCache.put(beanName, object);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 缓存不为null，直接返回</span></span><br><span class="line">            <span class="keyword">return</span> object;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 不为单例或者缓存中不存在</span></span><br><span class="line">        Object object = doGetObjectFromFactoryBean(factory, beanName);</span><br><span class="line">        <span class="comment">// 后置处理</span></span><br><span class="line">        <span class="keyword">if</span> (shouldPostProcess) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                object = postProcessObjectFromFactoryBean(object, beanName);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                        beanName, <span class="string">&quot;Post-processing of FactoryBean&#x27;s object failed&quot;</span>, ex);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> object;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="doGetObjectFromFactoryBean"><a href="#doGetObjectFromFactoryBean" class="headerlink" title="doGetObjectFromFactoryBean"></a>doGetObjectFromFactoryBean</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> Object <span class="title">doGetObjectFromFactoryBean</span><span class="params">(<span class="keyword">final</span> FactoryBean&lt;?&gt; factory, <span class="keyword">final</span> String beanName)</span></span></span><br><span class="line"><span class="function">        <span class="keyword">throws</span> BeanCreationException </span>&#123;</span><br><span class="line"></span><br><span class="line">    Object object;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 权限验证</span></span><br><span class="line">        <span class="keyword">if</span> (System.getSecurityManager() != <span class="keyword">null</span>) &#123;</span><br><span class="line">            AccessControlContext acc = getAccessControlContext();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                object =</span><br><span class="line">                        AccessController.doPrivileged(</span><br><span class="line">                                (PrivilegedExceptionAction&lt;Object&gt;) factory::getObject, acc);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (PrivilegedActionException pae) &#123;</span><br><span class="line">                <span class="keyword">throw</span> pae.getException();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 直接调用 getObject() 方法</span></span><br><span class="line">            object = factory.getObject();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (FactoryBeanNotInitializedException ex) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCurrentlyInCreationException(beanName, ex.toString());</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                beanName, <span class="string">&quot;FactoryBean threw exception on object creation&quot;</span>, ex);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Do not accept a null value for a FactoryBean that&#x27;s not fully</span></span><br><span class="line">    <span class="comment">// initialized yet: Many FactoryBeans just return null then.</span></span><br><span class="line">    <span class="keyword">if</span> (object == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (isSingletonCurrentlyInCreation(beanName)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> BeanCurrentlyInCreationException(</span><br><span class="line">                    beanName,</span><br><span class="line">                    <span class="string">&quot;FactoryBean which is currently in creation returned null from getObject&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        object = <span class="keyword">new</span> NullBean();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> object;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="获取单例"><a href="#获取单例" class="headerlink" title="获取单例"></a>获取单例</h1><p>当缓存中不存在已经加载的单例bean时就需要从头开始bean的加载过程。</p>
<h2 id="getSingleton"><a href="#getSingleton" class="headerlink" title="getSingleton"></a>getSingleton</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">getSingleton</span><span class="params">(String beanName, ObjectFactory&lt;?&gt; singletonFactory)</span> </span>&#123;</span><br><span class="line">    Assert.notNull(beanName, <span class="string">&quot;Bean name must not be null&quot;</span>);</span><br><span class="line">    <span class="keyword">synchronized</span> (<span class="keyword">this</span>.singletonObjects) &#123;</span><br><span class="line">        <span class="comment">// 检查上锁的这段时间内该bean是否已经被加载过</span></span><br><span class="line">        Object singletonObject = <span class="keyword">this</span>.singletonObjects.get(beanName);</span><br><span class="line">        <span class="keyword">if</span> (singletonObject == <span class="keyword">null</span>) &#123; <span class="comment">// 为空，进行初始化</span></span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">this</span>.singletonsCurrentlyInDestruction) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationNotAllowedException(</span><br><span class="line">                        beanName,</span><br><span class="line">                        <span class="string">&quot;Singleton bean creation not allowed while singletons of this factory are in destruction &quot;</span></span><br><span class="line">                                + <span class="string">&quot;(Do not request a bean from a BeanFactory in a destroy method implementation!)&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (logger.isDebugEnabled()) &#123;</span><br><span class="line">                logger.debug(<span class="string">&quot;Creating shared instance of singleton bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 创建前置处理，记录加载状态，将该beanName记录到正在加载的bean的map中</span></span><br><span class="line">            beforeSingletonCreation(beanName);</span><br><span class="line">            <span class="keyword">boolean</span> newSingleton = <span class="keyword">false</span>;</span><br><span class="line">            <span class="keyword">boolean</span> recordSuppressedExceptions = (<span class="keyword">this</span>.suppressedExceptions == <span class="keyword">null</span>);</span><br><span class="line">            <span class="keyword">if</span> (recordSuppressedExceptions) &#123;</span><br><span class="line">                <span class="keyword">this</span>.suppressedExceptions = <span class="keyword">new</span> LinkedHashSet&lt;&gt;();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 初始化bean</span></span><br><span class="line">                singletonObject = singletonFactory.getObject();</span><br><span class="line">                newSingleton = <span class="keyword">true</span>;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IllegalStateException ex) &#123;</span><br><span class="line">                <span class="comment">// Has the singleton object implicitly appeared in the meantime -&gt;</span></span><br><span class="line">                <span class="comment">// if yes, proceed with it since the exception indicates that state.</span></span><br><span class="line">                singletonObject = <span class="keyword">this</span>.singletonObjects.get(beanName);</span><br><span class="line">                <span class="keyword">if</span> (singletonObject == <span class="keyword">null</span>) &#123;</span><br><span class="line">                    <span class="keyword">throw</span> ex;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (BeanCreationException ex) &#123;</span><br><span class="line">                <span class="keyword">if</span> (recordSuppressedExceptions) &#123;</span><br><span class="line">                    <span class="keyword">for</span> (Exception suppressedException : <span class="keyword">this</span>.suppressedExceptions) &#123;</span><br><span class="line">                        ex.addRelatedCause(suppressedException);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">throw</span> ex;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (recordSuppressedExceptions) &#123;</span><br><span class="line">                    <span class="keyword">this</span>.suppressedExceptions = <span class="keyword">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 创建后置处理，移除beanName的正在加载的记录</span></span><br><span class="line">                afterSingletonCreation(beanName);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (newSingleton) &#123;</span><br><span class="line">                <span class="comment">// 缓存该单例bean，并同时删除加载过程中记录的各种辅助状态</span></span><br><span class="line">                addSingleton(beanName, singletonObject);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回结果</span></span><br><span class="line">        <span class="keyword">return</span> singletonObject;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="准备创建bean"><a href="#准备创建bean" class="headerlink" title="准备创建bean"></a>准备创建bean</h1><p>单例bean的创建入口 createBean</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (mbd.isSingleton()) &#123; <span class="comment">// singleton 单例</span></span><br><span class="line">    sharedInstance =</span><br><span class="line">            getSingleton(</span><br><span class="line">                    beanName,</span><br><span class="line">                    () -&gt; &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            <span class="keyword">return</span> createBean(beanName, mbd, args);</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (BeansException ex) &#123;</span><br><span class="line">                            <span class="comment">// Explicitly remove instance from singleton cache: It</span></span><br><span class="line">                            <span class="comment">// might have been put there</span></span><br><span class="line">                            <span class="comment">// eagerly by the creation process, to allow for</span></span><br><span class="line">                            <span class="comment">// circular reference resolution.</span></span><br><span class="line">                            <span class="comment">// Also remove any beans that received a temporary</span></span><br><span class="line">                            <span class="comment">// reference to the bean.</span></span><br><span class="line">                            destroySingleton(beanName);</span><br><span class="line">                            <span class="keyword">throw</span> ex;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;);</span><br><span class="line">    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="createBean"><a href="#createBean" class="headerlink" title="createBean"></a>createBean</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">createBean</span><span class="params">(String beanName, RootBeanDefinition mbd, <span class="meta">@Nullable</span> Object[] args)</span> <span class="keyword">throws</span> BeanCreationException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">        <span class="keyword">this</span>.logger.trace(<span class="string">&quot;Creating instance of bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    RootBeanDefinition mbdToUse = mbd;</span><br><span class="line">    <span class="comment">// 解析class</span></span><br><span class="line">    Class&lt;?&gt; resolvedClass = <span class="keyword">this</span>.resolveBeanClass(mbd, beanName, <span class="keyword">new</span> Class[<span class="number">0</span>]);</span><br><span class="line">    <span class="keyword">if</span> (resolvedClass != <span class="keyword">null</span> &amp;&amp; !mbd.hasBeanClass() &amp;&amp; mbd.getBeanClassName() != <span class="keyword">null</span>) &#123;</span><br><span class="line">        mbdToUse = <span class="keyword">new</span> RootBeanDefinition(mbd);</span><br><span class="line">        mbdToUse.setBeanClass(resolvedClass);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 处理override属性（xml中lookup-method、replace-method的配置）</span></span><br><span class="line">        mbdToUse.prepareMethodOverrides();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (BeanDefinitionValidationException var9) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, <span class="string">&quot;Validation of method overrides failed&quot;</span>, var9);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Object beanInstance;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 实例化的前置处理</span></span><br><span class="line">        beanInstance = <span class="keyword">this</span>.resolveBeforeInstantiation(beanName, mbdToUse);</span><br><span class="line">        <span class="keyword">if</span> (beanInstance != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> beanInstance;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var10) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(mbdToUse.getResourceDescription(), beanName, <span class="string">&quot;BeanPostProcessor before instantiation of bean failed&quot;</span>, var10);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 创建bean</span></span><br><span class="line">        beanInstance = <span class="keyword">this</span>.doCreateBean(beanName, mbdToUse, args);</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">            <span class="keyword">this</span>.logger.trace(<span class="string">&quot;Finished creating instance of bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27;&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> beanInstance;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ImplicitlyAppearedSingletonException | BeanCreationException var7) &#123;</span><br><span class="line">        <span class="keyword">throw</span> var7;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var8) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(mbdToUse.getResourceDescription(), beanName, <span class="string">&quot;Unexpected exception during bean creation&quot;</span>, var8);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="resolveBeforeInstantiation-实例化前置处理器"><a href="#resolveBeforeInstantiation-实例化前置处理器" class="headerlink" title="resolveBeforeInstantiation 实例化前置处理器"></a>resolveBeforeInstantiation 实例化前置处理器</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">resolveBeforeInstantiation</span><span class="params">(String beanName, RootBeanDefinition mbd)</span> </span>&#123;</span><br><span class="line">    Object bean = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) &#123;</span><br><span class="line">        <span class="comment">// Make sure bean class is actually resolved at this point.</span></span><br><span class="line">        <span class="keyword">if</span> (!mbd.isSynthetic() &amp;&amp; hasInstantiationAwareBeanPostProcessors()) &#123;</span><br><span class="line">            Class&lt;?&gt; targetType = determineTargetType(beanName, mbd);</span><br><span class="line">            <span class="keyword">if</span> (targetType != <span class="keyword">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 实例化前的前置处理器，给子类一个修改bean的机会，返回的bean可能会是一个代理bean，用于AOP</span></span><br><span class="line">                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);</span><br><span class="line">                <span class="keyword">if</span> (bean != <span class="keyword">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// 实例化前的后置处理器，将注册的后处理器的postProcessAfterInitialization方法应用到该bean中（因为bean的创建只有一次，所以只能在这里应用）</span></span><br><span class="line">                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        mbd.beforeInstantiationResolved = (bean != <span class="keyword">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> bean;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="doCreateBean-常规创建bean"><a href="#doCreateBean-常规创建bean" class="headerlink" title="doCreateBean 常规创建bean"></a>doCreateBean 常规创建bean</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">doCreateBean</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">        <span class="keyword">final</span> String beanName, <span class="keyword">final</span> RootBeanDefinition mbd, <span class="keyword">final</span> <span class="meta">@Nullable</span> Object[] args)</span></span></span><br><span class="line"><span class="function">        <span class="keyword">throws</span> BeanCreationException </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Instantiate the bean.</span></span><br><span class="line">    BeanWrapper instanceWrapper = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (mbd.isSingleton()) &#123;</span><br><span class="line">        <span class="comment">// 单例bean，从缓存中移除</span></span><br><span class="line">        instanceWrapper = <span class="keyword">this</span>.factoryBeanInstanceCache.remove(beanName);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (instanceWrapper == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 根据指定bean使用的初始化策略创建新的实例</span></span><br><span class="line">        instanceWrapper = createBeanInstance(beanName, mbd, args);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">final</span> Object bean = instanceWrapper.getWrappedInstance();</span><br><span class="line">    Class&lt;?&gt; beanType = instanceWrapper.getWrappedClass();</span><br><span class="line">    <span class="keyword">if</span> (beanType != NullBean.class) &#123;</span><br><span class="line">        mbd.resolvedTargetType = beanType;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 允许后置处理器修改合并后的bean定义类</span></span><br><span class="line">    <span class="comment">// Allow post-processors to modify the merged bean definition.</span></span><br><span class="line">    <span class="keyword">synchronized</span> (mbd.postProcessingLock) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!mbd.postProcessed) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// bean合并后的处理，@Autoword、@Resource注解通过该方法实现预解析</span></span><br><span class="line">                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                        mbd.getResourceDescription(),</span><br><span class="line">                        beanName,</span><br><span class="line">                        <span class="string">&quot;Post-processing of merged bean definition failed&quot;</span>,</span><br><span class="line">                        ex);</span><br><span class="line">            &#125;</span><br><span class="line">            mbd.postProcessed = <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Eagerly cache singletons to be able to resolve circular references</span></span><br><span class="line">    <span class="comment">// even when triggered by lifecycle interfaces like BeanFactoryAware.</span></span><br><span class="line">    <span class="comment">// 是否需要提前曝光：当且仅当</span></span><br><span class="line">    <span class="keyword">boolean</span> earlySingletonExposure =</span><br><span class="line">            (mbd.isSingleton() <span class="comment">// 为单例bean</span></span><br><span class="line">                    &amp;&amp; <span class="keyword">this</span>.allowCircularReferences <span class="comment">// 允许循环依赖</span></span><br><span class="line">                    &amp;&amp; isSingletonCurrentlyInCreation(beanName)); <span class="comment">// 正在创建中</span></span><br><span class="line">    <span class="keyword">if</span> (earlySingletonExposure) &#123;</span><br><span class="line">        <span class="keyword">if</span> (logger.isTraceEnabled()) &#123;</span><br><span class="line">            logger.trace(</span><br><span class="line">                    <span class="string">&quot;Eagerly caching bean &#x27;&quot;</span></span><br><span class="line">                            + beanName</span><br><span class="line">                            + <span class="string">&quot;&#x27; to allow for resolving potential circular references&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 避免后期循环依赖，可以在bean初始化完成前将创建实例的ObjectFactory加入工厂</span></span><br><span class="line">        <span class="comment">// 提前曝光其对应的ObjectFactory，将其加入singletonFactories缓存池中</span></span><br><span class="line">        addSingletonFactory(</span><br><span class="line">                beanName,</span><br><span class="line">                <span class="comment">// 对bean再一次依赖引用，其中AOP就是在这里将advice动态织入bean中，若没有则直接返回bean，不作任何处理</span></span><br><span class="line">                () -&gt; getEarlyBeanReference(beanName, mbd, bean));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 属性填充</span></span><br><span class="line">    <span class="comment">// Initialize the bean instance.</span></span><br><span class="line">    Object exposedObject = bean;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 填充bean，若存在依赖于其他bean的属性，递归</span></span><br><span class="line">        populateBean(beanName, mbd, instanceWrapper);</span><br><span class="line">        <span class="comment">// 调用初始化方式，如init-method</span></span><br><span class="line">        exposedObject = initializeBean(beanName, exposedObject, mbd);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable ex) &#123;</span><br><span class="line">        <span class="keyword">if</span> (ex <span class="keyword">instanceof</span> BeanCreationException</span><br><span class="line">                &amp;&amp; beanName.equals(((BeanCreationException) ex).getBeanName())) &#123;</span><br><span class="line">            <span class="keyword">throw</span> (BeanCreationException) ex;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                    mbd.getResourceDescription(),</span><br><span class="line">                    beanName,</span><br><span class="line">                    <span class="string">&quot;Initialization of bean failed&quot;</span>,</span><br><span class="line">                    ex);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 允许提前曝光的前提下要先检测是否存在循环依赖</span></span><br><span class="line">    <span class="keyword">if</span> (earlySingletonExposure) &#123;</span><br><span class="line">        <span class="comment">// 获取单例（与之不同的是，</span></span><br><span class="line">        <span class="comment">// 这里的false代表不需要对应的ObjectFactory调取getObject方法来创建bean，</span></span><br><span class="line">        <span class="comment">// 而只是从两个缓存map中检查是否有相应的bean</span></span><br><span class="line">        Object earlySingletonReference = getSingleton(beanName, <span class="keyword">false</span>);</span><br><span class="line">        <span class="comment">// 当earlySingletonReference不为null时，说明存在循环依赖</span></span><br><span class="line">        <span class="keyword">if</span> (earlySingletonReference != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="comment">// exposedObject == bean 说明exposedObject没有在初始化方法中被改变，即未被增强</span></span><br><span class="line">            <span class="keyword">if</span> (exposedObject == bean) &#123;</span><br><span class="line">                exposedObject = earlySingletonReference;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!<span class="keyword">this</span>.allowRawInjectionDespiteWrapping &amp;&amp; hasDependentBean(beanName)) &#123;</span><br><span class="line">                <span class="comment">// 获取依赖bean</span></span><br><span class="line">                String[] dependentBeans = getDependentBeans(beanName);</span><br><span class="line">                Set&lt;String&gt; actualDependentBeans = <span class="keyword">new</span> LinkedHashSet&lt;&gt;(dependentBeans.length);</span><br><span class="line">                <span class="comment">// 检测依赖</span></span><br><span class="line">                <span class="keyword">for</span> (String dependentBean : dependentBeans) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) &#123;</span><br><span class="line">                        actualDependentBeans.add(dependentBean);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 因为bean创建后其所依赖的bean一定是已创建的，</span></span><br><span class="line"><span class="comment">                 * actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有被全部创建完， 也就是说存在循环依赖</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">if</span> (!actualDependentBeans.isEmpty()) &#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> BeanCurrentlyInCreationException(</span><br><span class="line">                            beanName,</span><br><span class="line">                            <span class="string">&quot;Bean with name &#x27;&quot;</span></span><br><span class="line">                                    + beanName</span><br><span class="line">                                    + <span class="string">&quot;&#x27; has been injected into other beans [&quot;</span></span><br><span class="line">                                    + StringUtils.collectionToCommaDelimitedString(</span><br><span class="line">                                            actualDependentBeans)</span><br><span class="line">                                    + <span class="string">&quot;] in its raw version as part of a circular reference, but has eventually been &quot;</span></span><br><span class="line">                                    + <span class="string">&quot;wrapped. This means that said other beans do not use the final version of the &quot;</span></span><br><span class="line">                                    + <span class="string">&quot;bean. This is often the result of over-eager type matching - consider using &quot;</span></span><br><span class="line">                                    + <span class="string">&quot;&#x27;getBeanNamesForType&#x27; with the &#x27;allowEagerInit&#x27; flag turned off, for example.&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Register bean as disposable.</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 根据scope注册bean</span></span><br><span class="line">        registerDisposableBeanIfNecessary(beanName, bean, mbd);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (BeanDefinitionValidationException ex) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                mbd.getResourceDescription(), beanName, <span class="string">&quot;Invalid destruction signature&quot;</span>, ex);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> exposedObject;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="createBeanInstance-创建bean实例"><a href="#createBeanInstance-创建bean实例" class="headerlink" title="createBeanInstance 创建bean实例"></a>createBeanInstance 创建bean实例</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> BeanWrapper <span class="title">createBeanInstance</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">        String beanName, RootBeanDefinition mbd, <span class="meta">@Nullable</span> Object[] args)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 解析class</span></span><br><span class="line">    <span class="comment">// Make sure bean class is actually resolved at this point.</span></span><br><span class="line">    Class&lt;?&gt; beanClass = resolveBeanClass(mbd, beanName);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (beanClass != <span class="keyword">null</span></span><br><span class="line">            &amp;&amp; !Modifier.isPublic(beanClass.getModifiers())</span><br><span class="line">            &amp;&amp; !mbd.isNonPublicAccessAllowed()) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> BeanCreationException(</span><br><span class="line">                mbd.getResourceDescription(),</span><br><span class="line">                beanName,</span><br><span class="line">                <span class="string">&quot;Bean class isn&#x27;t public, and non-public access not allowed: &quot;</span></span><br><span class="line">                        + beanClass.getName());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Supplier&lt;?&gt; instanceSupplier = mbd.getInstanceSupplier();</span><br><span class="line">    <span class="keyword">if</span> (instanceSupplier != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> obtainFromSupplier(instanceSupplier, beanName);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果工厂方法不为空，使用工厂方法初始化策略</span></span><br><span class="line">    <span class="keyword">if</span> (mbd.getFactoryMethodName() != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> instantiateUsingFactoryMethod(beanName, mbd, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Shortcut when re-creating the same bean...</span></span><br><span class="line">    <span class="keyword">boolean</span> resolved = <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">boolean</span> autowireNecessary = <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">if</span> (args == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 一个类有多个构造函数，各有不同的参数</span></span><br><span class="line">        <span class="comment">// 调用前需要先根据参数锁定构造函数或其对应的工厂方法</span></span><br><span class="line">        <span class="keyword">synchronized</span> (mbd.constructorArgumentLock) &#123;</span><br><span class="line">            <span class="comment">// 该判断过程比较消耗性能，所以采用缓存机制，</span></span><br><span class="line">            <span class="comment">// 可以直接从该属性 mbd.resolvedConstructorOrFactoryMethod 的缓存值中去取</span></span><br><span class="line">            <span class="keyword">if</span> (mbd.resolvedConstructorOrFactoryMethod != <span class="keyword">null</span>) &#123;</span><br><span class="line">                resolved = <span class="keyword">true</span>;</span><br><span class="line">                autowireNecessary = mbd.constructorArgumentsResolved;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 如果已经解析过则使用解析好的构造函数方法，不需要再次锁定</span></span><br><span class="line">    <span class="keyword">if</span> (resolved) &#123;</span><br><span class="line">        <span class="keyword">if</span> (autowireNecessary) &#123;</span><br><span class="line">            <span class="comment">// 构造函数自动注入</span></span><br><span class="line">            <span class="keyword">return</span> autowireConstructor(beanName, mbd, <span class="keyword">null</span>, <span class="keyword">null</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 默认构造函数构造</span></span><br><span class="line">            <span class="keyword">return</span> instantiateBean(beanName, mbd);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 需要根据参数解析构造函数</span></span><br><span class="line">    <span class="comment">// Candidate constructors for autowiring?</span></span><br><span class="line">    Constructor&lt;?&gt;[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);</span><br><span class="line">    <span class="keyword">if</span> (ctors != <span class="keyword">null</span></span><br><span class="line">            || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR</span><br><span class="line">            || mbd.hasConstructorArgumentValues()</span><br><span class="line">            || !ObjectUtils.isEmpty(args)) &#123;</span><br><span class="line">        <span class="keyword">return</span> autowireConstructor(beanName, mbd, ctors, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Preferred constructors for default construction?</span></span><br><span class="line">    ctors = mbd.getPreferredConstructors();</span><br><span class="line">    <span class="keyword">if</span> (ctors != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> autowireConstructor(beanName, mbd, ctors, <span class="keyword">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// No special handling: simply use no-arg constructor.</span></span><br><span class="line">    <span class="keyword">return</span> instantiateBean(beanName, mbd);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>暂到这里吧。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><h2 id="口头梳理"><a href="#口头梳理" class="headerlink" title="口头梳理"></a>口头梳理</h2><p><strong>bean加载过程：</strong>拿到beanname后先尝试从单例缓存池中拿（防止循环依赖），如果拿到了说明存在这个bean已经有实例或者存在循环依赖，对其实例化并返回。拿不到就根据这个bean的作用域去创建对应bean，如果自己创建不了就交给父类工厂创建（如果有父类工厂的话），创建之前要先检查都没有动态配置依赖bean，也就是depend-on属性，如果有的话要先加载被依赖的bean。创建完了再对其实例化。</p>
<p><strong>bean的实例化过程：</strong>因为拿到的bean都只是最原始的bean状态，并不一定是我们最终想要的bean。要对拿到的bean做一个正确性的检查。譬如我们想要的是factorybean但是拿到了bean，这就是一个错误。如果想要bean但是拿到了factorybean，那就调用该factorybean的getObject方法拿到他加载的bean。</p>
<p><strong>单例bean创建过程：</strong>首先也是从单例缓存池中拿，拿到了就直接返回。拿不到才正式开始创建，第一步就是先记录加载状态，spring维护了一个set作加载池，所有正在加载的bean的beanname都会被放在这个加载池里。记录之后正式开始根据其ObjectFactory定义的getObject方法开始创建。创建完之后移除创建过程中记录的各种辅助状态（包括正在加载状态）并将这个bean实例放入单例缓存池即可。</p>
<p><strong>单例bean的具体创建过程：</strong>先做一些准备工作，包括一些属性的处理（如override）、实例化的前置处理（aop判断），如果在后者拿到了一个bean则直接返回（可能是一个代理bean）。如果没拿到则继续常规bean的创建，先根据对应的策略创建新的实例（工厂方法、构造函数自动注入、简单初始化），之后在允许提前曝光的前提下将这个bean实例及其对应ObjectFactory放到二级缓存中（避免后期循环依赖）。之后便对bean实例进行属性填充，也即依赖注入。在属性填充过程中会若发现需要注入其他bean，则递归去加载其他bean。</p>
<h2 id="简单总结"><a href="#简单总结" class="headerlink" title="简单总结"></a>简单总结</h2><ol>
<li><p>去单例池（三层缓存）找单例</p>
</li>
<li><ol>
<li>找到了，从中获取obj，直接返回<strong>⬆</strong></li>
</ol>
</li>
<li><p>创建bean（单例总结）</p>
</li>
<li><ol>
<li>记录加载状态</li>
<li>创建bean</li>
</ol>
</li>
<li><ol>
<li><ol>
<li>实例化前置处理（BeanPostProcessor接口的注册在这里应用，比如AOP代理增强，直接返回<strong>⬆</strong>）</li>
<li>创建bean实例（解析构造器）</li>
<li>@Autowird，@Resource</li>
<li>提前曝光（单例&amp;&amp;allowEarlyReference&amp;&amp;该bean正在加载中）</li>
</ol>
</li>
</ol>
</li>
<li><ol start="3">
<li>后置处理，清除加载状态，注册bean</li>
</ol>
</li>
</ol>
<h2 id="流程图"><a href="#流程图" class="headerlink" title="流程图"></a>流程图</h2><div class="gallery ">
              <p><img src="https://typora-yayako.oss-cn-hangzhou.aliyuncs.com/spring%20bean%E5%8A%A0%E8%BD%BD.jpg" class="lazyload" data-srcset="https://typora-yayako.oss-cn-hangzhou.aliyuncs.com/spring%20bean%E5%8A%A0%E8%BD%BD.jpg" srcset="" alt="spring bean加载"></p>
            </div>

<h1 id="几个问题"><a href="#几个问题" class="headerlink" title="几个问题"></a>几个问题</h1><h2 id="怎么解决循环依赖"><a href="#怎么解决循环依赖" class="headerlink" title="怎么解决循环依赖"></a>怎么解决循环依赖</h2><p>spring在创建单例bean的时候会提前曝光（前提是允许提前曝光，具体就是三个判断 单例&amp;&amp;允许循环依赖&amp;&amp;正在创建中），在创建的时候将自己的ObjectFactory放到二级缓存中，在循环注入的时候直接能从缓存中取出对应的ObjectFactory并调用getObject方法获取bean实例（原生状态），同时将这个bean实例放入三级缓存中，将ObjectFactory从二级缓存中除去。那么在多层循环依赖（假设都依赖A）的情况下，之后递归加载A直接从二级缓存中取即可，也不必再使用ObjectFactory生产bean。</p>
<h2 id="缓存两层就够了，为什么要三层"><a href="#缓存两层就够了，为什么要三层" class="headerlink" title="缓存两层就够了，为什么要三层"></a>缓存两层就够了，为什么要三层</h2><p>二级缓存存的是ObjectFactory，提前放出ObjectFactory我们已经可以根据其定义的getObject()方法获取想要的bean，为什么还要定义一个三级缓存？</p>
<p>三级缓存里实际放的就是通过这个ObjectFactory得到的bean实例，得到的结果都是一样的，之所以设置一个三级缓存是因为getObject获取bean的操作十分复杂，不如维护一个缓存池直接取来得方便，并且可以在源码中看到，当通过二级缓存中的工厂获取bean后就会将其放入三级缓存，同时，就会将这个工厂从二级缓存中移除。在代码中你确实会发现，在getSingleton方法中，先查找的一级缓存，第二找的，就是三级缓存，就是为了避免重复通过工厂创建bean。尤其是在多重循环依赖的情况下。</p>
<h2 id="BeanFactory和FactoryBean和ObjectFactory"><a href="#BeanFactory和FactoryBean和ObjectFactory" class="headerlink" title="BeanFactory和FactoryBean和ObjectFactory"></a>BeanFactory和FactoryBean和ObjectFactory</h2><p><strong>BeanFactory：</strong>ioc容器的顶级接口，ioc容器的最基础实现，提供了一些列接口。<img src="https://cdn.nlark.com/yuque/0/2020/png/1143661/1591324187097-c0f2d89f-a8e3-47d7-b7d1-e7ae2823611e.png" class="lazyload" data-srcset="https://cdn.nlark.com/yuque/0/2020/png/1143661/1591324187097-c0f2d89f-a8e3-47d7-b7d1-e7ae2823611e.png" srcset="" alt="image"></p>
<p><strong>FactoryBean：</strong>工厂bean，可以生产bean的bean。想要获取工厂bean的时候在beanname前加个‘&amp;’即可。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/1143661/1591324451016-6cb0a005-362f-4bb4-ac34-0a7966437457.png" class="lazyload" data-srcset="https://cdn.nlark.com/yuque/0/2020/png/1143661/1591324451016-6cb0a005-362f-4bb4-ac34-0a7966437457.png" srcset="" alt="image"></p>
<p><strong>ObjectFactory：</strong>一个简单工厂接口，提供了getObject方法用于创建bean。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2020/png/1143661/1591324274280-92bcc912-9e90-4470-97ac-471deb0f63e8.png" class="lazyload" data-srcset="https://cdn.nlark.com/yuque/0/2020/png/1143661/1591324274280-92bcc912-9e90-4470-97ac-471deb0f63e8.png" srcset="" alt="image"></p>

  
  
    
    <div class='footer'>
      
      
      
        <div class='copyright'>
          <blockquote>
            
              
                <p>博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议</p>

              
            
              
                <p>本文永久链接是：<a href=https://www.yayako.cn/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/>https://www.yayako.cn/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</a></p>
              
            
          </blockquote>
        </div>
      
      
    </div>
  
  
    


  <div class='article-meta' id="bottom">
    <div class='new-meta-box'>
      
        
          <div class="new-meta-item date" itemprop="dateUpdated" datetime="2021-01-23T00:19:50+08:00">
  <a class='notlink'>
    <i class="fas fa-edit fa-fw" aria-hidden="true"></i>
    <p>更新于：2021年1月23日</p>
  </a>
</div>

        
      
        
          
  
  <div class="new-meta-item meta-tags"><a class="tag" href="/tags/%E6%BA%90%E7%A0%81/" rel="nofollow"><i class="fas fa-hashtag fa-fw" aria-hidden="true"></i><p>源码</p></a></div> <div class="new-meta-item meta-tags"><a class="tag" href="/tags/Spring/" rel="nofollow"><i class="fas fa-hashtag fa-fw" aria-hidden="true"></i><p>Spring</p></a></div>


        
      
        
          
  <div class="new-meta-item share -mob-share-list">
  <div class="-mob-share-list share-body">
    
      
        <a class="-mob-share-qq" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=https://www.yayako.cn/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/&title=Spring Bean加载 源码解析 - Yayako's Blog&summary=Spring是如何实现bean加载的？Spring是如何创建单例bean如何解决循环依赖的的？"
          
          >
          
            <img src="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qq.png" class="lazyload" data-srcset="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qq.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-qzone" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://www.yayako.cn/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/&title=Spring Bean加载 源码解析 - Yayako's Blog&summary=Spring是如何实现bean加载的？Spring是如何创建单例bean如何解决循环依赖的的？"
          
          >
          
            <img src="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qzone.png" class="lazyload" data-srcset="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qzone.png" srcset="">
          
        </a>
      
    
      
        <a class="-mob-share-weibo" title="" rel="external nofollow noopener noreferrer noopener"
          
          target="_blank" href="http://service.weibo.com/share/share.php?url=https://www.yayako.cn/2020/06/07/Spring%20Bean%E5%8A%A0%E8%BD%BD%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/&title=Spring Bean加载 源码解析 - Yayako's Blog&summary=Spring是如何实现bean加载的？Spring是如何创建单例bean如何解决循环依赖的的？"
          
          >
          
            <img src="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/weibo.png" class="lazyload" data-srcset="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/weibo.png" srcset="">
          
        </a>
      
    
      
    
      
    
  </div>
</div>



        
      
    </div>
  </div>


  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/2020/06/07/Spring%20AOP%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/'>
          <p class='title'><i class="fas fa-chevron-left" aria-hidden="true"></i>Spring AOP 源码解析</p>
          <p class='content'>jdk动态代理与cglib代理的区别在spring aop的实现中，

如果目标对象实现了接口，默认情况下会采用jdk动态代理实现aop，也可以强制使用cglib实现aop（添加库，配置prox...</p>
        </a>
      
      
        <a class='next' href='/2020/04/29/String.intern()/'>
          <p class='title'>有关String.intern()<i class="fas fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>
intern()1public String intern()

api
Returns a canonical representation for the string object.

...</p>
        </a>
      
    </div>
  
</article>


  

  <article class="post white-box reveal shadow" id="comments">
    <p ct><i class='fas fa-comments'></i> 评论</p>
    
    <div id="valine_container" class="valine_thread">
  <i class="fas fa-cog fa-spin fa-fw fa-2x"></i>
</div>

  </article>






</div>
<aside class='l_side'>
  
  
    
    



  <section class="widget toc-wrapper shadow desktop mobile" id="toc-div" >
    
  <header>
    
      <i class="fas fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-%E8%BD%AC%E6%8D%A2%E5%AF%B9%E5%BA%94beanName"><span class="toc-text">1. 转换对应beanName</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-%E5%B0%9D%E8%AF%95%E4%BB%8E%E7%BC%93%E5%AD%98%E4%B8%AD%E5%8A%A0%E8%BD%BD%E5%8D%95%E4%BE%8B%E5%B9%B6%E5%B0%86%E5%85%B6%E5%AE%9E%E4%BE%8B%E5%8C%96"><span class="toc-text">2. 尝试从缓存中加载单例并将其实例化</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%BE%9D%E8%B5%96%E6%A3%80%E6%9F%A5"><span class="toc-text">3. 原型模式的依赖检查</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-%E6%A3%80%E6%B5%8BparentBeanFactory"><span class="toc-text">4. 检测parentBeanFactory</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-%E5%B0%86%E5%AD%98%E5%82%A8XML%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84GernericBeanDefinition%E8%BD%AC%E6%8D%A2%E4%B8%BARootBeanDefinition"><span class="toc-text">5. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-%E5%AF%BB%E6%89%BE%E4%BE%9D%E8%B5%96%EF%BC%88depend-on%EF%BC%89"><span class="toc-text">6. 寻找依赖（depend-on）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-%E9%92%88%E5%AF%B9%E4%B8%8D%E5%90%8C%E7%9A%84scope%E8%BF%9B%E8%A1%8Cbean%E7%9A%84%E5%88%9B%E5%BB%BA"><span class="toc-text">7. 针对不同的scope进行bean的创建</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2"><span class="toc-text">8. 类型转换</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#getObjectForBeanInstance"><span class="toc-text">getObjectForBeanInstance</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#getObjectFromFactoryBean"><span class="toc-text">getObjectFromFactoryBean</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#doGetObjectFromFactoryBean"><span class="toc-text">doGetObjectFromFactoryBean</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#getSingleton"><span class="toc-text">getSingleton</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#createBean"><span class="toc-text">createBean</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#resolveBeforeInstantiation-%E5%AE%9E%E4%BE%8B%E5%8C%96%E5%89%8D%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-text">resolveBeforeInstantiation 实例化前置处理器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#doCreateBean-%E5%B8%B8%E8%A7%84%E5%88%9B%E5%BB%BAbean"><span class="toc-text">doCreateBean 常规创建bean</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#createBeanInstance-%E5%88%9B%E5%BB%BAbean%E5%AE%9E%E4%BE%8B"><span class="toc-text">createBeanInstance 创建bean实例</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%A3%E5%A4%B4%E6%A2%B3%E7%90%86"><span class="toc-text">口头梳理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E5%8D%95%E6%80%BB%E7%BB%93"><span class="toc-text">简单总结</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%81%E7%A8%8B%E5%9B%BE"><span class="toc-text">流程图</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%8E%E4%B9%88%E8%A7%A3%E5%86%B3%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96"><span class="toc-text">怎么解决循环依赖</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BC%93%E5%AD%98%E4%B8%A4%E5%B1%82%E5%B0%B1%E5%A4%9F%E4%BA%86%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%B8%89%E5%B1%82"><span class="toc-text">缓存两层就够了，为什么要三层</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#BeanFactory%E5%92%8CFactoryBean%E5%92%8CObjectFactory"><span class="toc-text">BeanFactory和FactoryBean和ObjectFactory</span></a></li></ol>
    </div>
  </section>


  


</aside>


   <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<script>
  window.pdata={}
  pdata.ispage=true;
  pdata.postTitle="Spring Bean加载 源码解析";
  pdata.commentPath="";
  pdata.commentPlaceholder="";

  var l_header=document.getElementById("l_header");
  
  l_header.classList.remove("show");
  
</script>
 
        </div>
        
  
  <footer class="footer clearfix">
    <br><br>
    
      
        <div class="aplayer-container">
          


        </div>
      
    
      
        <br>
        <div class="social-wrapper">
          
            
          
            
          
            
          
        </div>
      
    
      
        <div><p>博客内容遵循 <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议</a></p>
</div>
      
    
      
        
          <div><p><span id="lc-sv">本站总访问量为 <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span> 次</span> <span id="lc-uv">访客数为 <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span> 人</span></p>
</div>
        
      
    
      
        
      
    
      
        <div class='copyright'>
        <p><a href="/about/">Copyright © 2021 扭秧歌的一只泱</a> <strong>|</strong> <img src="https://yayako-blog.oss-cn-hangzhou.aliyuncs.com/settings/%E5%A4%87%E6%A1%88%E5%9B%BE%E6%A0%87.png" class="lazyload" data-srcset="https://yayako-blog.oss-cn-hangzhou.aliyuncs.com/settings/%E5%A4%87%E6%A1%88%E5%9B%BE%E6%A0%87.png" srcset="" alt="备案图标"> <a target="_blank" rel="noopener" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=33032402002017">浙公网安备33032402002017号</a> <strong>|</strong> <a target="_blank" rel="noopener" href="https://beian.miit.gov.cn/#/Integrated/index">浙ICP备20015559号</a></p>

        </div>
      
    
  </footer>


        <a
          id="s-top"
          class="fas fa-arrow-up fa-fw"
          href="javascript:void(0)"
        ></a>
      </div>
    </div>
    <div>
      <script>
window.volantis={};
window.volantis.loadcss=document.getElementById("loadcss");
/********************脚本懒加载函数********************************/
function loadScript(src, cb) {
var HEAD = document.getElementsByTagName('head')[0] || document.documentElement;
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
if (cb) script.onload = cb;
script.setAttribute('src', src);
HEAD.appendChild(script);
}
//https://github.com/filamentgroup/loadCSS
var loadCSS = function( href, before, media, attributes ){
	var doc = window.document;
	var ss = doc.createElement( "link" );
	var ref;
	if( before ){
		ref = before;
	}
	else {
		var refs = ( doc.body || doc.getElementsByTagName( "head" )[ 0 ] ).childNodes;
		ref = refs[ refs.length - 1];
	}
	var sheets = doc.styleSheets;
	if( attributes ){
		for( var attributeName in attributes ){
			if( attributes.hasOwnProperty( attributeName ) ){
				ss.setAttribute( attributeName, attributes[attributeName] );
			}
		}
	}
	ss.rel = "stylesheet";
	ss.href = href;
	ss.media = "only x";
	function ready( cb ){
		if( doc.body ){
			return cb();
		}
		setTimeout(function(){
			ready( cb );
		});
	}
	ready( function(){
		ref.parentNode.insertBefore( ss, ( before ? ref : ref.nextSibling ) );
	});
	var onloadcssdefined = function( cb ){
		var resolvedHref = ss.href;
		var i = sheets.length;
		while( i-- ){
			if( sheets[ i ].href === resolvedHref ){
				return cb();
			}
		}
		setTimeout(function() {
			onloadcssdefined( cb );
		});
	};
	function loadCB(){
		if( ss.addEventListener ){
			ss.removeEventListener( "load", loadCB );
		}
		ss.media = media || "all";
	}
	if( ss.addEventListener ){
		ss.addEventListener( "load", loadCB);
	}
	ss.onloadcssdefined = onloadcssdefined;
	onloadcssdefined( loadCB );
	return ss;
};
</script>
<script>
  
  loadCSS("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.14/css/all.min.css", window.volantis.loadcss);
  
  
  
  
</script>
<!-- required -->

<script src="https://cdn.jsdelivr.net/npm/jquery@3.5/dist/jquery.min.js"></script>

<script>
  function pjax_fancybox() {
    $(".md .gallery").find("img").each(function () { //渲染 fancybox
      var element = document.createElement("a"); // a 标签
      $(element).attr("class", "fancybox");
      $(element).attr("pjax-fancybox", "");  // 过滤 pjax
      $(element).attr("href", $(this).attr("src"));
      if ($(this).attr("data-original")) {
        $(element).attr("href", $(this).attr("data-original"));
      }
      $(element).attr("data-fancybox", "images");
      var caption = "";   // 描述信息
      if ($(this).attr('alt')) {  // 判断当前页面是否存在描述信息
        $(element).attr('data-caption', $(this).attr('alt'));
        caption = $(this).attr('alt');
      }
      var div = document.createElement("div");
      $(div).addClass("fancybox");
      $(this).wrap(div); // 最外层套 div ，其实主要作用还是 class 样式
      var span = document.createElement("span");
      $(span).addClass("image-caption");
      $(span).text(caption); // 加描述
      $(this).after(span);  // 再套一层描述
      $(this).wrap(element);  // 最后套 a 标签
    })
    $(".md .gallery").find("img").fancybox({
      selector: '[data-fancybox="images"]',
      hash: false,
      loop: false,
      closeClick: true,
      helpers: {
        overlay: {closeClick: true}
      },
      buttons: [
        "zoom",
        "close"
      ]
    });
  };
  function SCload_fancybox() {
    if ($(".md .gallery").find("img").length == 0) return;
    loadCSS("https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css", document.getElementById("loadcss"));
    setTimeout(function() {
      loadScript('https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js', pjax_fancybox)
    }, 1);
  };
  $(function () {
    SCload_fancybox();
  });
</script>


<!-- internal -->

  
  
  
    
<script src="https://cdn.jsdelivr.net/npm/jquery-backstretch@2.1.18/jquery.backstretch.min.js"></script>

    <script type="text/javascript">
        var imgs=["https://yayako-blog.oss-cn-hangzhou.aliyuncs.com/cover/hd.jpg"];
        if ('false' == 'true') {
          function shuffle(arr){
            /*From countercurrent-time*/
            var n = arr.length;
            while(n--) {
              var index = Math.floor(Math.random() * n);
              var temp = arr[index];
              arr[index] = arr[n];
              arr[n] = temp;
            }
          }
          shuffle(imgs);
        }
	  function Pjax_backstretch(){
        
          $.backstretch(
            imgs,
          {
            duration: "10000",
            fade: "1500"
          });
        
	  }
	  loadScript("https://cdn.jsdelivr.net/npm/jquery-backstretch@2.1.18/jquery.backstretch.min.js",Pjax_backstretch)
    </script>
  




<script>
  function loadIssuesJS() {
    if ($(".md").find(".issues-api").length == 0) return;
    setTimeout(function() {
	
	  loadScript('/js/issues.js');
	
    }, 1);
  };
  $(function () {
    loadIssuesJS();
  });
</script>



  <script defer src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@17.1.0/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  
  
    <script>
      window.FPConfig = {
        delay: 0,
        ignoreKeywords: [],
        maxRPS: 5,
        hoverDelay: 25
      };
    </script>
    <script defer src="https://cdn.jsdelivr.net/gh/gijo-varghese/flying-pages@2.1.2/flying-pages.min.js"></script>
  




  <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
    var clipboard = new ClipboardJS('.btn-copy', {
        target: function (trigger) {
            return trigger.nextElementSibling
        }
    });
    function wait(callback, seconds) {
        var timelag = null;
        timelag = window.setTimeout(callback, seconds)
    }
    function pjax_initCopyCode() {
		if($(".highlight .code pre").length+$(".article pre code").length==0)return;
        var copyHtml = '';
        copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
        copyHtml += '<i class="fas fa-copy"></i><span>COPY</span>';
        copyHtml += '</button>';
        $(".highlight .code pre").before(copyHtml);
        $(".article pre code").before(copyHtml);
        clipboard.off('success').on('success', function (e) {
            let $btn = $(e.trigger);
            $btn.addClass('copied');
            let $icon = $($btn.find('i'));
            $icon.removeClass('fa-copy');
            $icon.addClass('fa-check-circle');
            let $span = $($btn.find('span'));
            $span[0].innerText = 'COPIED';
            wait(function () {
                $icon.removeClass('fa-check-circle');
                $icon.addClass('fa-copy');
                $span[0].innerText = 'COPY'
            }, 2000)
        });
        clipboard.off('error').on('error', function (e) {
            e.clearSelection();
            let $btn = $(e.trigger);
            $btn.addClass('copy-failed');
            let $icon = $($btn.find('i'));
            $icon.removeClass('fa-copy');
            $icon.addClass('fa-times-circle');
            let $span = $($btn.find('span'));
            $span[0].innerText = 'COPY FAILED';
            wait(function () {
                $icon.removeClass('fa-times-circle');
                $icon.addClass('fa-copy');
                $span[0].innerText = 'COPY'
            }, 2000)
        })
    }
    $(function () {
        pjax_initCopyCode()
    });
</script>




   <script src="https://cdn.jsdelivr.net/npm/scrollreveal@4.0.6/dist/scrollreveal.min.js"></script>
<script type="text/javascript">
  function pjax_scrollrebeal() {
    ScrollReveal().reveal('.l_main .reveal', {
      distance: '32px',
      duration: '800',
      interval: '20',
      scale: '1',
      easing: 'ease-out'
    });
  }
  $(function () {
    pjax_scrollrebeal();
  });
</script>






  
  
<script src="https://cdn.jsdelivr.net/npm/valine@1.4/dist/Valine.min.js"></script>


<script>
  function emoji(path, idx, ext) {
    return path + "/" + path + "-" + idx + "." + ext;
  }
  var emojiMaps = {};
  for (var i = 1; i <= 54; i++) {
    emojiMaps['tieba-' + i] = emoji('tieba', i, 'png');
  }
  for (var i = 1; i <= 101; i++) {
    emojiMaps['qq-' + i] = emoji('qq', i, 'gif');
  }
  for (var i = 1; i <= 116; i++) {
    emojiMaps['aru-' + i] = emoji('aru', i, 'gif');
  }
  for (var i = 1; i <= 125; i++) {
    emojiMaps['twemoji-' + i] = emoji('twemoji', i, 'png');
  }
  for (var i = 1; i <= 4; i++) {
    emojiMaps['weibo-' + i] = emoji('weibo', i, 'png');
  }
  function pjax_valine() {
    if(!document.querySelectorAll("#valine_container")[0])return;
    let pagePlaceholder = pdata.commentPlaceholder || "快来评论吧~";
    let path = pdata.commentPath;
    if (path.length == 0) {
      let defaultPath = '';
      path = defaultPath || decodeURI(window.location.pathname);
    }
    var valine = new Valine();
    valine.init(Object.assign({"js":"https://cdn.jsdelivr.net/npm/valine@1.4/dist/Valine.min.js","path":null,"placeholder":"快来评论吧~","appId":"crkoKrezsl4I7UWQjAvOy2N1-gzGzoHsz","appKey":"OUvAeTn1CnCmGFdNYVH00G0S","meta":["nick","mail","link"],"requiredFields":["nick","mail"],"enableQQ":true,"recordIP":false,"avatar":"robohash","pageSize":10,"lang":"zh-cn","highlight":true,"visitor":true,"mathJax":false}, {
      el: '#valine_container',
      path: path,
      placeholder: pagePlaceholder,
      emojiCDN: 'https://cdn.jsdelivr.net/gh/volantis-x/cdn-emoji/valine/',
      emojiMaps: emojiMaps,
    }))
  }
  $(function () {
    pjax_valine();
  });
</script>





  
<script src="/js/app.js"></script>



<!-- optional -->

  <script>
const SearchServiceimagePath="https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/img/";
const ROOT =  ("/" || "/").endsWith('/') ? ("/" || "/") : ("//" || "/" );

$('.input.u-search-input').one('focus',function(){
	
		loadScript('/js/search/hexo.js',setSearchService);
	
})

function listenSearch(){
  
    customSearch = new HexoSearch({
      imagePath: SearchServiceimagePath
    });
  
}
function setSearchService() {
	listenSearch();
	
		document.addEventListener("pjax:success", listenSearch);
	
}
</script>











  <script defer>

  const LCCounter = {
    app_id: 'u9j57bwJod4EDmXWdxrwuqQT-MdYXbMMI',
    app_key: 'jfHtEKVE24j0IVCGHbvuFClp',
    custom_api_server: '',

    // 查询存储的记录
    getRecord(Counter, url, title) {
      return new Promise(function (resolve, reject) {
        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({url})))
          .then(resp => resp.json())
          .then(({results, code, error}) => {
            if (code === 401) {
              throw error;
            }
            if (results && results.length > 0) {
              var record = results[0];
              resolve(record);
            } else {
              Counter('post', '/classes/Counter', {url, title: title, times: 0})
                .then(resp => resp.json())
                .then((record, error) => {
                  if (error) {
                    throw error;
                  }
                  resolve(record);
                }).catch(error => {
                console.error('Failed to create', error);
                reject(error);
              });
            }
          }).catch((error) => {
          console.error('LeanCloud Counter Error:', error);
          reject(error);
        });
      })
    },

    // 发起自增请求
    increment(Counter, incrArr) {
      return new Promise(function (resolve, reject) {
        Counter('post', '/batch', {
          "requests": incrArr
        }).then((res) => {
          res = res.json();
          if (res.error) {
            throw res.error;
          }
          resolve(res);
        }).catch((error) => {
          console.error('Failed to save visitor count', error);
          reject(error);
        });
      });
    },

    // 构建自增请求体
    buildIncrement(objectId) {
      return {
        "method": "PUT",
        "path": `/1.1/classes/Counter/${ objectId }`,
        "body": {
          "times": {
            '__op': 'Increment',
            'amount': 1
          }
        }
      }
    },

    // 校验是否为有效的 UV
    validUV() {
      var key = 'LeanCloudUVTimestamp';
      var flag = localStorage.getItem(key);
      if (flag) {
        // 距离标记小于 24 小时则不计为 UV
        if (new Date().getTime() - parseInt(flag) <= 86400000) {
          return false;
        }
      }
      localStorage.setItem(key, new Date().getTime().toString());
      return true;
    },

    addCount(Counter) {
      var enableIncr = '' === 'true' && window.location.hostname !== 'localhost';
      enableIncr = true;
      var getterArr = [];
      var incrArr = [];
      // 请求 PV 并自增
      var pvCtn = document.querySelector('#lc-sv');
      if (pvCtn || enableIncr) {
        var pvGetter = this.getRecord(Counter, 'https://www.yayako.cn' + '/#lc-sv', 'Visits').then((record) => {
          incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-sv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + 1;
              if (pvCtn) {
                pvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(pvGetter);
      }

      // 请求 UV 并自增
      var uvCtn = document.querySelector('#lc-uv');
      if (uvCtn || enableIncr) {
        var uvGetter = this.getRecord(Counter, 'https://www.yayako.cn' + '/#lc-uv', 'Visitors').then((record) => {
          var vuv = this.validUV();
          vuv && incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-uv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + (vuv ? 1 : 0);
              if (uvCtn) {
                uvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(uvGetter);
      }

      // 请求文章的浏览数，如果是当前页面就自增
      var allPV = document.querySelectorAll('#lc-pv');
      if (allPV.length > 0 || enableIncr) {
        for (i = 0; i < allPV.length; i++) {
          let pv = allPV[i];
          let title = pv.getAttribute('data-title');
          var url = 'https://www.yayako.cn' + pv.getAttribute('data-path');
          if (url) {
            var viewGetter = this.getRecord(Counter, url, title).then((record) => {
              // 是当前页面就自增
              let curPath = window.location.pathname;
              if (curPath.includes('index.html')) {
                curPath = curPath.substring(0, curPath.lastIndexOf('index.html'));
              }
              if (pv.getAttribute('data-path') == curPath) {
                incrArr.push(this.buildIncrement(record.objectId));
              }
              if (pv) {
                var ele = pv.querySelector('#lc-pv #number');
                if (ele) {
                  if (pv.getAttribute('data-path') == curPath) {
                    ele.innerText = (record.times || 0) + 1;
                  } else {
                    ele.innerText = record.times || 0;
                  }
                  pv.style.display = 'inline';
                }
              }
            });
            getterArr.push(viewGetter);
          }
        }
      }

      // 如果启动计数自增，批量发起自增请求
      if (enableIncr) {
        Promise.all(getterArr).then(() => {
          incrArr.length > 0 && this.increment(Counter, incrArr);
        })
      }

    },


    fetchData(api_server) {
      var Counter = (method, url, data) => {
        return fetch(`${ api_server }/1.1${ url }`, {
          method,
          headers: {
            'X-LC-Id': this.app_id,
            'X-LC-Key': this.app_key,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      this.addCount(Counter);
    },

    refreshCounter() {
      var api_server = this.app_id.slice(-9) !== '-MdYXbMMI' ? this.custom_api_server : `https://${ this.app_id.slice(0, 8).toLowerCase() }.api.lncldglobal.com`;
      if (api_server) {
        this.fetchData(api_server);
      } else {
        fetch('https://app-router.leancloud.cn/2/route?appId=' + this.app_id)
          .then(resp => resp.json())
          .then(({api_server}) => {
            this.fetchData('https://' + api_server);
          });
      }
    }

  };

  LCCounter.refreshCounter();

  document.addEventListener('pjax:complete', function () {
    LCCounter.refreshCounter();
  });
</script>








<script>
function listennSidebarTOC() {
  const navItems = document.querySelectorAll(".toc li");
  if (!navItems.length) return;
  const sections = [...navItems].map((element) => {
    const link = element.querySelector(".toc-link");
    const target = document.getElementById(
      decodeURI(link.getAttribute("href")).replace("#", "")
    );
    link.addEventListener("click", (event) => {
      event.preventDefault();
      window.scrollTo({
		top: target.offsetTop + 100,
		
		behavior: "smooth"
		
	  });
    });
    return target;
  });

  function activateNavByIndex(target) {
    if (target.classList.contains("active-current")) return;

    document.querySelectorAll(".toc .active").forEach((element) => {
      element.classList.remove("active", "active-current");
    });
    target.classList.add("active", "active-current");
    let parent = target.parentNode;
    while (!parent.matches(".toc")) {
      if (parent.matches("li")) parent.classList.add("active");
      parent = parent.parentNode;
    }
  }

  function findIndex(entries) {
    let index = 0;
    let entry = entries[index];
    if (entry.boundingClientRect.top > 0) {
      index = sections.indexOf(entry.target);
      return index === 0 ? 0 : index - 1;
    }
    for (; index < entries.length; index++) {
      if (entries[index].boundingClientRect.top <= 0) {
        entry = entries[index];
      } else {
        return sections.indexOf(entry.target);
      }
    }
    return sections.indexOf(entry.target);
  }

  function createIntersectionObserver(marginTop) {
    marginTop = Math.floor(marginTop + 10000);
    let intersectionObserver = new IntersectionObserver(
      (entries, observe) => {
        let scrollHeight = document.documentElement.scrollHeight + 100;
        if (scrollHeight > marginTop) {
          observe.disconnect();
          createIntersectionObserver(scrollHeight);
          return;
        }
        let index = findIndex(entries);
        activateNavByIndex(navItems[index]);
      },
      {
        rootMargin: marginTop + "px 0px -100% 0px",
        threshold: 0,
      }
    );
    sections.forEach((element) => {
      element && intersectionObserver.observe(element);
    });
  }
  createIntersectionObserver(document.documentElement.scrollHeight);
}

document.addEventListener("DOMContentLoaded", listennSidebarTOC);
document.addEventListener("pjax:success", listennSidebarTOC);
</script>

<!-- more -->

  


<script src="https://cdn.jsdelivr.net/npm/pjax@0.2.8/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox])',
        selectors: [
          "title",
          "#l_cover",
          "#pjax-container",
          "#pjax-header-nav-list"
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      window.subData = null; // 移除标题（用于一二级导航栏切换处）
      if (typeof $.fancybox != "undefined") {
        $.fancybox.close();    // 关闭弹窗
      }
      volantis.$switcher.removeClass('active'); // 关闭移动端激活的搜索框
      volantis.$header.removeClass('z_search-open'); // 关闭移动端激活的搜索框
      volantis.$wrapper.removeClass('sub'); // 跳转页面时关闭二级导航

      // 解绑事件 避免重复监听
      volantis.$topBtn.unbind('click');
      $('.menu a').unbind('click');
      $(window).unbind('resize');
      $(window).unbind('scroll');
      $(document).unbind('scroll');
      $(document).unbind('click');
      $('body').unbind('click');
	  
    });

    document.addEventListener('pjax:complete', function () {
      // 关于百度统计对 SPA 页面的处理：
      // 方案一：百度统计>管理>单页应用设置中，打开开启按钮即可对SPA进行统计。 https://tongji.baidu.com/web/help/article?id=324
      // 方案二：取消注释下列代码。 https://tongji.baidu.com/web/help/article?id=235
       

      // 关于谷歌统计对 SPA 页面的处理：
      // 当应用以动态方式加载内容并更新地址栏中的网址时，也应该更新通过 gtag.js 存储的网页网址。
      // https://developers.google.cn/analytics/devguides/collection/gtagjs/single-page-applications?hl=zh-cn
      


      $('.nav-main').find('.list-v').not('.menu-phone').removeAttr("style",""); // 移除小尾巴的移除
      $('.menu-phone.list-v').removeAttr("style",""); // 移除小尾巴的移除
      $('script[data-pjax], .pjax-reload script').each(function () {
        $(this).parent().append($(this).remove());
      });
      try{
          if (typeof $.fancybox == "undefined") {
            SCload_fancybox();
          } else {
            pjax_fancybox();
          }
        
		  Pjax_backstretch()
        
        
        
          pjax_scrollrebeal();
        
        if (typeof IssuesAPI == "undefined") {
          loadIssuesJS();
        }
        
          pjax_initCopyCode();
        
        
          pjax_valine();
        
        
        
        
        
        
      } catch (e) {
        console.log(e);
      }
	  
    });

    document.addEventListener('pjax:error', function (e) {
	  
      window.location.href = e.triggerElement.href;
    });
</script>
 
    </div>
  </body>
</html>
